package main

import "fmt"

/*
	通道的发送和接收操作都有哪些基本的特性？
	1.对于同一个通道，发送操作之间是互斥的，接收操作之间也是互斥的。
	2.发送操作和接收操作中对元素值的处理都是不可分割的。
	3.发送操作在完全完成之前会被阻塞。接收操作也是如此。

	元素值从外界进入通道时会被复制。更具体地说，进入通道的并不是在接收操作符右边的那个元素值，而是它的副本。

	元素值从通道进入外界时会被移动。这个移动操作实际上包含了两步，
		第一步是生成正在通道中的这个元素值的副本，并准备给到接收方。
		第二步是删除在通道中的这个元素值。

问题 1：发送操作和接收操作在什么时候可能被长时间的阻塞？
	针对缓冲通道的情况。如果通道已满，那么对它的所有发送操作都会被阻塞，直到通道中有元素值被接收走。

	由于发送操作在这种情况下被阻塞后，它们所在的 goroutine 会顺序地进入通道内部的发送等待队列，所以通知的顺序总是公平的。

	相对的，如果通道已空，那么对它的所有接收操作都会被阻塞，直到通道中有新的元素值出现。
	这时，通道会通知最早等待的那个接收操作所在的 goroutine，并使它再次执行接收操作。

	因此而等待的、所有接收操作所在的 goroutine，都会按照先后顺序被放入通道内部的接收等待队列。

	对于非缓冲通道，无论是发送操作还是接收操作，一开始执行就会被阻塞，直到配对的操作也开始执行，才会继续传递。
	由此可见，非缓冲通道是在用同步的方式传递数据。也就是说，只有收发双方对接上了，数据才会被传递。

	对于值为nil的通道，不论它的具体类型是什么，对它的发送操作和接收操作都会永久地处于阻塞状态。

	注意，由于通道类型是引用类型，所以它的零值就是nil。
	换句话说，当只声明该类型的变量但没有用make函数对它进行初始化时，该变量的值就会是nil。一定不要忘记初始化通道！

问题 2：发送操作和接收操作在什么时候会引发 panic？
	对于一个已初始化，但并未关闭的通道来说，收发操作一定不会引发 panic。但是通道一旦关闭，再对它进行发送操作，就会引发 panic。

	如果试图关闭一个已经关闭了的通道，也会引发 panic。注意，接收操作是可以感知到通道的关闭的，并能够安全退出。

	当把接收表达式的结果同时赋给两个变量时，第二个变量的类型就是一定bool类型。它的值如果为false就说明通道已经关闭，并且再没有元素值可取了。

	如果通道关闭时，里面还有元素值未被取出，那么接收表达式的第一个结果，仍会是通道中的某一个元素值，而第二个结果值一定会是true。

	由于通道的收发操作有上述特性，所以除非有特殊的保障措施，千万不要让接收方关闭通道，而应当让发送方做这件事。
*/
func main() {

	channel01 :=make(chan int, 3)

	channel01 <- 2
	channel01 <- 1
	channel01 <- 3

	element := <- channel01

	fmt.Printf("The first element received from channel channel01: %v\n",  element)
}
